﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;

namespace EBookStore.Books
{
    /// <summary>
    /// Singleton class
    /// </summary>
    [DebuggerDisplay("Books:{Books.Count}")]
    public class Catalog
    {

        #region Singleton
        private static Catalog _instance = null;
        private static object _syncObj = new object();


        /// <summary>
        /// 
        /// </summary>
        public int Count
        {
            get { return Books.Count; }
        }

        /// <summary>
        /// Catalog instance
        /// </summary>
        public static Catalog Instance
        {
            get
            {
                if (_instance == null)
                {
                    lock (_syncObj)
                    {
                        if (_instance == null)
                        {
                            _instance = new Catalog();
                        }
                    }
                }
                return _instance;
            }
        } 
        #endregion

        /// <summary>
        /// List of books in catalog.
        /// </summary>
        private List<Book> Books = null;
        private List<BookComment> _comments = null;

        /// <summary>
        /// asdas
        /// </summary>
        private Catalog()
        {
            Books = new List<Book>();
            _comments = new List<BookComment>();
        }


        /// <summary>
        /// Adds comment to Book
        /// </summary>
        /// <param name="book"></param>
        /// <param name="user"></param>
        /// <param name="text"></param>
        /// <returns></returns>
        [AOP.NotNullOrConcreteObject(Index = 0, BaseType = typeof(Book), Message = "Book is null")]
        [AOP.NotNullOrConcreteObject(Index = 0, BaseType = typeof(Users.User), Message = "User is null")]
        [AOP.NotNullOrConcreteObject(Index = 0, BaseType = typeof(string), Message = "no comment")]
        public bool AddComment(Book book, Users.User user, string text)
        {
            if (FindBook(book.ISBN) != null)
            {
                _comments.Add(new BookComment(book, user, text));
                return true;
            }
            else
            {
                return false;
            }
        }


        /// <summary>
        /// View book's comments
        /// </summary>
        /// <param name="ISBN"></param>
        /// <returns></returns>
        public IEnumerable<BookComment> ViewComments(string ISBN)
        {
            return (from el in _comments where el.Book.ISBN.Equals(ISBN) select el).ToArray();
        }


        #region Book Functions

        /// <summary>
        /// 
        /// </summary>
        /// <param name="books"></param>
        /// <returns></returns>
        public bool AddBooks(IEnumerable<Book> books)
        {
            foreach (Book b in books)
            {
                AddBook(b);
            }
            return true;
        }

        /// <summary>
        /// Add book to catalog if such ISBN does not exists already.
        /// </summary>
        /// <param name="book"></param>
        /// <returns></returns>
        public bool AddBook(Book book)
        {
            Book b = FindBook(book.ISBN);
            if (b != null)
                throw new Exception("This book already exists in catalog");
            else
            {
                Books.Add(book);
                return true;
            }
        }

        /// <summary>
        /// Searches for book by ISBN, if found removes it.
        /// </summary>
        /// <param name="book"></param>
        /// <returns></returns>
        public bool RemoveBook(Book book)
        {
            return RemoveBook(book.ISBN);
        }


        /// <summary>
        /// Removes book by ISBN number.
        /// </summary>
        /// <param name="ISBN"></param>
        /// <returns></returns>
        public bool RemoveBook(string ISBN)
        {
            Book b = FindBook(ISBN);
            if (b != null)
            {
                Books.Remove(b);
                return true;
            }
            return false;
        }


        /// <summary>
        /// Remove all books from catalog.
        /// </summary>
        public void Clear()
        {
            Books.Clear();
        }
        
        #endregion
        
        #region Iterator

        /// <summary>
        /// Class iterator.
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        public Book this[int index]
        {
            get { return Books[index]; }
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="ISBN"></param>
        /// <returns></returns>
        public Book this[string ISBN]
        {
            get { return FindBook(ISBN); }
        }

        #endregion

        /// <summary>
        /// find book by isbn number.
        /// </summary>
        /// <param name="ISBN"></param>
        /// <returns>Book object or null</returns>
        private Book FindBook(string ISBN)
        {
            return (from el in Books where el.ISBN.Equals(ISBN) select el).FirstOrDefault();
        }


        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public List<Book> ViewCatalog(Users.User user)
        {
            // here based on user we can return differnt catalog list
            return Books;
        }




        /// <summary>
        /// 
        /// </summary>
        /// <returns></returns>
        public Books.Book[] ToArray()
        {
            return Books.ToArray();
        }
    }
}
